<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>合集</title>
</head>

<body>
    <h3>script 标签中的 async 和 defer 的作用</h3>
    <ul>
        <li><b>属性只对外部连接有效</b></li>
        <li>
            <p>没有添加属性的时候，当浏览器遇到 script 则会立刻加载并执行，并且会阻塞后面的内容。</p>
        </li>
        <li>
            <p>有 async 则会异步加载 script 的内容，不会阻塞后面的内容加载</p>
        </li>
        <li>
            <p>有 defer 同意也是一步加载，但是里面的内容则会在所有元素解析完成后执行</p>
        </li>
    </ul>


    <hr>


    <h3>setTimeout 最小执行时间是多少？</h3>
    <p>HTML 5 规定的事件</p>
    <p>setTimeout 是 4ms</p>
    <p>setInterval 是 10ms</p>

    <hr>


    <h3>ES6 和 ES5 有什么区别？</h3>
    <p>JS 是由 ECMAScript BOM DOM 组成</p>
    <p>ES6 是 ES5 的升级版，是 JS 下一个版本的标准</p>


    <hr>

    <h3>ES6的新特性有哪些？</h3>
    <ol>
        <li>
            <p><b>新增了块级作用域声明 (let,const)</b></p>
            <ul>
                <li>不存在变量提升</li>
                <li>存在暂时性死区问题</li>
                <li>块级作用域内容</li>
                <li>不能再同一个作用域内重复声明</li>
            </ul>
        </li>
        <li>新增了定义类的语法躺 (class)</li>
        <li>
            <p><b>新增了一种基本类型数据 (symbol)</b></p>
            <p>唯一类型</p>
        </li>
        <li>
            <p>新增了解构赋值，从数组或对象中取值，然后给变量赋值</p>
        </li>
        <li>新增了函数参数的默认值</li>
        <li>数组 API</li>
        <li>对象和数组新增了扩展运算符</li>
        <li>
            <p><b>Promise</b></p>
            <ul>
                <li>解决回调地狱问题</li>
                <li>自身有 all, reject, resolve, race</li>
                <li>原型上有 then, catch</li>
                <li>把异步操作队列化</li>
                <li>pending 初始状态, fulfilled 操作成功, rejected 操作失败</li>
                <li>流程状态只有两种: pending -> fulfilled; pending -> rejected; </li>
                <li>async await: 搭配使用 <br />async 表明函数内有异步操作, 调用函数会返回 Promise <br /> await 是组成 async 的表达式，结果是取决于它等待的内容。
                </li>
            </ul>
        </li>
        <li>模块化(import, export)</li>
        <li>
            <p><b>set和map</b></p>
            <p>set 不重复</p>
            <p>map 的 key 的类型不受限制</p>
        </li>
        <li>
            <p><b>generator</b></p>
        </li>
        <li>
            <p><b>箭头函数</b></p>
            <p>箭头函数和普通函数的区别</p>
            <ul>
                <li>不能作为构造函数使用，不能用 new</li>
                <li>没有原型</li>
                <li>箭头函数没有 arguments</li>
                <li>箭头函数不能用 call, apply, bind 去改变 this 执行</li>
                <li>this 指向外层的第一个函数的第一个 this</li>
            </ul>
        </li>
    </ol>

    <hr>

    <h3>call, apply, bind 三者有什么区别</h3>
    <p>都是改变了 this 指向和函数的调用, call 和 apply 功能类似，只是传参的方法不同</p>
    <ul>
        <li>call 方法传递是一个参数列表</li>
        <li>apply 方法传的是一个数组</li>
        <li>bind 传参后不会立即执行，会返回一个改变了 this 指向的函数，这个函数还是可以传参的</li>
        <li>call 方法要比 apply 性能好一些，所以用 call 的更多一些</li>
    </ul>

    <hr>

    <h3>用递归的时候有没有遇到什么问题？</h3>
    <p>如果一个函数内可以调用函数本身，那么这个就是递归函数</p>
    <p>函数内部调用自己必须得有 return, 不然会导致栈溢出, 内存泄漏</p>


    <hr>

    <h3>如何实现一个深拷贝？</h3>
    <p>深拷贝就是完全拷贝一份新的对象，同时在堆内存中重新开辟空间。</p>
    <p>拷贝的对象被修改后，原对象不对影响</p>
    <p>主要针对引用类型</p>
    <ul>
        <li>扩展运算符</li>
        <li>JSON.parse(JSON.stringify())</li>
        <li>利用递归函数实现</li>
    </ul>

    <hr>

    <h3>事件循环</h3>
    <p>单线程脚本语言</p>
    <p>主线程 执行栈 任务队列 宏任务 微任务</p>
    <p>
        <b>主线程需要先执行同步任务，然后才去执行任务队列的任务，如果在执行宏任务之前有微任务，那么要先执行微任务</b>
    </p>

    <hr>

    <h3>ajax 是什么呢？怎么实现的？</h3>
    <p>他是可以在不重新加载网页下，可以实现与服务器交换数据并更新部分内容；</p>
    <p>通过 XMLHttpRequest 对象向服务器发送异步请求，然后从服务器拿到数据，最后通过 JS 操作 DOM 更新页面；</p>
    <ol>
        <li>创建 XMLHttpRequest 对象</li>
        <li>通过 xmh 对象里的 open() 方法和服务器就案例连接</li>
        <li>构建请求所需的数据，并通过 xmh 对象的 send() 发送给服务器</li>
        <li>通过 xmh 对象 onReadyState changes 事件监听服务器和你的通信状态</li>
        <li>接受并处理服务器的响应结果</li>
        <li>把处理的数据更新到 HTML 页面上</li>
    </ol>

    <hr>

    <h3>get 和 post 的区别？</h3>
    <ol>
        <li>get 一般是获取数据，post 一般是提交数据</li>
        <li>get 参数会放在 url 上，安全性比较差</li>
        <li>post 是放在 body 中，数据长度是没有限制的</li>
        <li>get 请求刷新服务器是没有影响的，post 请求退回是会重新提交数据</li>
        <li>get 请求时会被缓存，post 请求不会被缓存</li>
        <li>get 请求会被保存在浏览器历史记录中， post 不会</li>
        <li>get 只能通过 url 进行请求，post 请求支持很多种</li>
    </ol>

    <hr>

    <h3>Promise 的内部原理？它的缺点是什么</h3>
    <ol>
        <li>Promise 对象，封装了一个异步操作并且可以获取成功和失败的结果</li>
        <li>Promise 是为了解决回调地狱问题产生的，通过 .then 依次处理</li>
        <li>回调地狱有多个异步执行操作，并且每一个操作结果都需要依赖前一个操作结果，导致代码中嵌套大量的回调函数，可维护性差</li>
        <li>Promise 对象有三种状态：pending(进行中)、fulfilled(已成功)、rejected(已失败)</li>
    </ol>
    <p>缺点：无法取消 Promise，一旦创建它就会立即执行，不能中途取消，不使用回调函数（then）无法得到结果</p>
    <p>原理：需要构造一个 Promise 实例，实例需要传递函数的参数，两个形参是函数类型分别：resolve, reject</p>

    <script>
        {
            setTimeout(() => {
                console.log(456);
            }, 1000)

            const promise = new Promise((resolve, reject) => {
                const random = Math.random();
                setTimeout(() => {
                    if (random < 0.5) {
                        const data = { message: "Hello, Promise!" };
                        resolve(data); // 返回成功结果给 Promise
                    } else {
                        reject(new Error("Failed to fetch data.")); // 返回失败信息给 Promise
                    }
                }, 0)
            });
            promise.then(data => {
                console.log(data);
            }).catch(error => {
                console.log(error);
            })

            console.log(123); // 123 高于异步请求先输出
        }
    </script>

    <hr>

    <h3>Promise 和 async await 的区别？</h3>
    <ol>
        <li>都是处理异步请求的方式</li>
        <li>promise 是 ES6，async await 是 ES7 的语法</li>
        <li>async await 是基于 promise 实现的，他和 promise 都是非阻塞性的</li>
        <li>
            <b>优缺点：</b>
            <ol>
                <li>Promise 是返回对象，我们要用 then 和 catch 方法处理，并且书写方式是链式，容易造成代码重叠，不好维护。async await 是通过 try catch 进行捕获异常；</li>
                <li>async await 最大的优点就是让代码看起来像同步一样，只要遇到 await 就会立刻返回结果，然后再执行下面的代码；</li>
                <li>promise.then() 的方式返回，会出现请求还没返回就执行了后面的操作</li>
            </ol>
        </li>
    </ol>

    <hr>

    <h3>浏览器缓存有哪些？</h3>
    <ol>
        <li>
            <b>cookies</b>
            <ol>
                <li>h5 标准前的一个本地存储方式</li>
                <li>优点：兼容性好、请求头自带 cookie</li>
                <li>缺点：存储量少、如果一个请求不需要的 cookie, 会造成资源浪费</li>
            </ol>
        </li>
        <li>
            <b>localStorage</b>
            <ol>
                <li>h5 加入的以键值对标准的方式</li>
                <li>优点：操作方便，永久存储，兼容性较好</li>
                <li>缺点：保存值类型被限制，浏览器在隐私模式下不可读取，不能被爬虫</li>
            </ol>
        </li>
        <li>
            <b>sessionStorage</b>
            <ol>
                <li>跟 localStorage 差不多</li>
                <li>会话级别的存储，关闭浏览器或者页面标签之后就会删除，同源窗口无法共享存储。</li>
            </ol>
        </li>
        <li>
            <b>indexedDB</b>
            <p>h5 加入的以键值对标准的方式，可以快速读取，适合 WEB 场景；</p>
        </li>
    </ol>

    <hr>

    <h3>token 存在 sessionStorage 还是 localStorage ?</h3>
    <ol>
        <li>存在 localStorage 的话，每次接口请求都需要当成一个字段传给后台</li>
        <li>存在 cookie， 会自动发送，缺点就是不能跨域</li>
        <li>一般建议不敏感的信息可以存在本地存储，反之可以选择 cookie </li>
        <li>存在本地容易被 XSS 攻击</li>
        <li>存在 cookie 中会有 CSRF 攻击</li>
        <li>综上所诉存在本地会更好，做好对于的措施，那么利大于弊</li>
    </ol>

    <hr>

    <h3>token 登录流程</h3>
    <ol>
        <li>客户端用账号密码请求登录</li>
        <li>服务端收到请求后，需要验证账号密码</li>
        <li>验证成功之后，服务端会签发一个 token 把这个 token 发送给客户端</li>
        <li>客户端收到 token 后保存起来，可以放在 cookie 或者本地存储</li>
        <li>客户端每次向服务端发送请求资源时候，都需要带上这个 token</li>
        <li>服务端收到请求，验证客户端的 token 成之后返回数据</li>
    </ol>

    <hr>

    <h3>页面渲染过程？</h3>
    <ol>
        <li>DNS 解析</li>
        <li>建立 TCP 连接</li>
        <li>发送 HTTP 请求</li>
        <li>服务器处理请求返回</li>
        <li>
            <b>渲染页面</b>
            <ul>
                <li>浏览器会获取 HTML 和 CSS 资源，然后把 HTML 解析成 DOM 树</li>
                <li>再把 CSS 解析成 CSSOM</li>
                <li>把 DOM 和 CSSOM 合并成渲染树</li>
                <li>布局</li>
                <li>把渲染树每个节点渲染到屏幕上</li>
            </ul>
        </li>
        <li>断开 TCP 连接</li>
    </ol>

    <hr>

    <h3>DOM 树和渲染树有什么区别？</h3>
    <ol>
        <li>DOM 树是和 html 标签一一对应的，包含 head 和隐藏元素</li>
        <li>渲染树是不包含 head 和隐藏元素的</li>
    </ol>

    <hr>
    <h3>精灵图和 base64 的区别？</h3>
    <p>精灵图是所有小图合并的一张大图，可以减少资源请求，css 需要通过定位来显示。</p>
    <p>base64 是把图片转换成代码的形式，在会增加 css 体积，它会和 html css 一起下载到浏览器中，减少请求，但是一些低版本不支持</p>

    <hr>
    <h3>svg 格式了解多少？</h3>
    <ol>
        <li>它是基于 xml 语法格式的图像，可缩放矢量图，其他图像是基于像素的，SVG 是属于堆图像形状的描述，本质是文本文件，体积小，放多少倍都不会失真</li>
        <li>可以直接插入页面中，称为 DOM 一部分，然后用 JS 或者 CSS 进行操作</li>
        <li>可以作用 img src 引入</li>
        <li>SVG 可以转为 base64 引入页面</li>
    </ol>

    <hr>
    <h3>了解过 JWT 吗？</h3>
    <p>JSON Wen Token：它是通过 JSON 形式作为在 web 应用中的令牌，可以在各方面之间安全的把信息作为 JSON 对象传输</p>
    <ol>
        <li><b>三个部分组成：</b></li>
        <li>Header（头部）：包含了使用的加密算法和令牌的类型等信息。</li>
        <li>Payload（负载）：存储了关于用户的声明信息，如用户ID、角色、权限等。</li>
        <li>Signature（签名）：使用指定的密钥对Header和Payload进行签名，以保证令牌的完整性和防止篡改。</li>
    </ol>
    <ol>
        <li><b>验证流程：</b></li>
        <li>前端输入账号密码向请求后端验证</li>
        <li>后端验证成功后，把用户 ID 等其他信息作为 JWT 负载，把它和头部分贝进行 base64 编码进行拼接签名，行程一个 JWT （token）</li>
        <li>前端每日请求时都会把 JWT 放在 HTTP 请求头的 Authorization 字段内</li>
        <li>后端检查是否存在，如果存在就验证 JWT 的有效性（签名是否正确，token 是否过期）</li>
        <li>验证通过后后端吧使用 JWT 中包含的用户信息进行其他操作，并返回对应结果</li>
    </ol>
    <ol>
        <li><b>特点：</b></li>
        <li>无状态：每个JWT都包含了完整的用户声明信息，服务器不需要在后台存储会话数据，因此具有良好的可扩展性。</li>
        <li>自包含：JWT中携带了用户声明信息，服务器解析JWT后即可获取相关信息，避免了多次查询数据库。</li>
        <li>防篡改：通过使用密钥对JWT进行签名，可以确保其内容在传输过程中不被篡改。</li>
    </ol>

    <hr>
    <h3>npm 底层环境是什么？</h3>
    <p>全程：node package manager，node 的包管理和分发工具，已经成为分发 node node 模块的标准</p>
    <p>npm 的组成：网站、注册表、命令行</p>

    <hr>
    <h3>HTTP 协议规定的协议头和请求头有什么？</h3>
    <ol>
        <li><b>请求头信息：</b>
            <ul>
                <li>Accept：浏览器告诉服务器所支持的数据类型</li>
                <li>Host：浏览器告诉服务器我想访问的服务器是哪台主机</li>
                <li>Referer：浏览器告诉服务器我是从哪里来的</li>
                <li>User-Agent：浏览器类型、版本信息</li>
                <li>Date：浏览器告诉服务器我是什么时候访问的</li>
                <li>Connection：连接方式</li>
                <li>Cookie</li>
                <li>X-Request-With：请求方式</li>
            </ul>
        </li>
        <li><b>响应头信息：</b>
            <ul>
                <li>Location：这个告诉浏览器你要去找谁</li>
                <li>Server：告诉浏览器服务器类型</li>
                <li>content-type：告诉浏览器返回的数据类型</li>
                <li>Refresh：控制了定时刷新</li>
            </ul>
        </li>
    </ol>

    <hr>
    <h3>浏览器缓存策略？</h3>
    <ol>
        <li>
            <b>强缓存（本地缓存）</b>
            <p>强缓存不发起 http 请求，直接使用缓存里的内容，浏览器把 JS css image 等存到内存中，下次用户芳魂直接从内存中去，提高性能</p>
        </li>
        <li>
            <b>弱缓存（协商缓存）</b>
            <p>弱缓存需要向后台发起请求，通过判断来决定是否使用协商缓存，如果请求内容没有变化，则返回 304，浏览器就用缓存里的内容</p>
        </li>
    </ol>

    <hr>
    <h3>什么是同源策略？</h3>
    <p>同源策略是浏览器的核心，如果没有这个策略就会遭受网络攻击</p>
    <p>主要指的就是：协议+域名+端口号三者一直，若其中一个不一样则不是同源，会产生跨域</p>
    <p>三个允许资源加载跨域的标签：img、link、script</p>
    <p>跨域是可以发送请求，后端会正常返回结果，只不过这个结果被浏览器拦截</p>
    <p>解决跨域需要的对方服务器支持，分别有以下这几种方法：JSONP、CORS、websocket、反向代理</p>

    <hr>
    <h3>防抖和节流</h3>
    <p>两个都是为了解决页面事件频繁触发的优化方案</p>
    <ol>
        <li>
            <p>防抖：避免事件重复触发，在设定的时间内交互事件只会执行一次</p>
            <p>场景：频繁和服务端交互、输入框的自动保存事件</p>
        </li>
        <li>
            <p>节流：把频繁的事件减少，每隔一段时间执行</p>
            <p>场景：滚动事件</p>
        </li>
    </ol>

    <hr>
    <h3>什么是 JSON</h3>
    <p>是一种存字符串形式的数据，它本身不提供任何方法，适合在网络中进行传输</p>
    <p>JSON 数据存在 .json 文件中，也可以吧 JSON 数据以字符串的形式保存在数据库中、cookie 中</p>
    <p>场景：定义接口；序列化；生成 token；配置文件package.json</p>

    <hr>
    <h3>无感登录？</h3>
    <p>无感登录就是检测到用户的 token 过期，不需要重新登录，自动的去刷新 token</p>
    <ul>
        <li>方法一：在响应器中拦截，判断 token 是否过期后调用刷新 token 的接口
            <ol>
                <li>登录成功后保存 token 和 refresh_token</li>
                <li>在响应器中对 401 状态码引入刷新 token 的 api 方法调用</li>
                <li>替换保存本地新的 token</li>
                <li>把错误对象里的 token 替换</li>
                <li>再次发送未完成的请求</li>
                <li>如果 refresh_token 过期了，判断是否过期，过期了就清楚所有 token 重新登陆</li>
            </ol>
        </li>
        <li>方法二：后端返回过期时间，前端判断时间去调用刷新 token 接口</li>
    </ul>

    <hr>
    <h3>大文件上传怎么处理？</h3>
    <ul>
        <li><b>分片上传:</b>
            <ol>
                <li>把需要上传的文件按照一定的规则，分割相同大小的数据块</li>
                <li>初始化一个分片上传任务，返回本次分片上传的唯一标识</li>
                <li>按照一定的规则把各个数据上传</li>
                <li>发送完成后，服务端会根据数据上传的完整性合并原始文件</li>
            </ol>
        </li>
    </ul>

    <hr>
    <h3>HTML 语义化的理解</h3>
    <ul>
        <li>在写 HTML 页面结构时所用的标签都是有意义的，用合适的标签去做合适的事情</li>
        <li>头部用 header、主体用 main、底部用 footer</li>
        <li>把页面 css 去掉了，页面如果较为正常，则已经语义化</li>
        <li>
            为什么要选择语义化
            <ol>
                <li>让 HTML 结构更清晰</li>
                <li>方便协作、利于开发</li>
                <li>利于爬虫和 seo</li>
                <li>能够让浏览器更好的去解析代码</li>
                <li>如果 css 未加载完成，可以优化用户体验</li>
            </ol>
        </li>
    </ul>

    <hr>
    <h3>H5C3的新特性</h3>
    <ul>
        <li>语义化的标签</li>
        <li>音视频标签</li>
        <li>canvas</li>
        <li>数据存储</li>
        <li>增加了表单空间</li>
        <li>拖拽释放 API </li>
    </ul>
    <ul>
        <li>选择器：属性选择器、伪类选择器、伪元素选择器</li>
        <li>媒体查询</li>
        <li>文字阴影</li>
        <li>边框</li>
        <li>盒子模型 box-sizing</li>
        <li>渐变</li>
        <li>动画过渡</li>
        <li>自定义动画</li>
        <li>背景的属性</li>
    </ul>

    <hr>
    <h3>rem 怎么做适配</h3>
    <p>它是相对根元素 HTML 的 font-size 定的，通常来做移动端的适配</p>
    <p>根据根元素的 font-size 值的倍数</p>

    <hr>
    <h4>解决过那些移动端的兼容问题？</h4>
    <ol>
        <li>当设置样式 overflow:auto/auto 时， iOS 上会卡顿，处理方式：-webkit-overflow:touch</li>
        <li>在安卓环境下 placeholder 文字设置行高时会偏上，处理方式：input 有placeholder属性时候，不要设置行高</li>
        <li>移动端字体小于 12px 异常显示可以用 transform 缩小</li>
        <li>iOS 的 input 设置了 disabled 属性为 true 显示异常，可以用 input[type=button]{ opcity: 1 }</li>
    </ol>

    <hr>
    <h3>v-show和 v-if 的区别</h3>
    <ul>
        <li>两个都是控制元素的显示隐藏</li>
        <li>v-show 是通过 css 控制，而 v-if 是添加和删除 DOM </li>
        <li>v-if 有一个局部加载/卸载过程，切换这个过程会销毁和重新建内部的时间监听</li>
        <li>v-if 是真正的条件渲染，触发它会更新生命周期，而 v-show 不会</li>
    </ul>

    <hr>
    <h3>如何理解MVVM</h3>
    <p>全称是 Model View ViewModel，一种前端开发架构模式</p>
    <ul>
        <li>M：模型，对应的就是 data 的数据</li>
        <li>V：视图，用户界面 DOM</li>
        <li>VM：视图模型 vue 实例对象，连接 View 和 Model 的桥梁，核心是提供对 View 和 ViewModel 的双向绑定，当数据改变时候，ViewModel 能监听到数据变化并自动更新视图 <br> 当用户操作视图的时候，的双向绑定，当数据改变时候，ViewModel 也可以监听到视图的变化，然后通知数据进行改动，这就实现了双向数据绑定</li>
    </ul>

    <hr>
    <h3>v-for 中的 key 值得作用是什么？</h3>
    <p>key 属性是 DOM 元素得唯一标识，赋予元素唯一标识，删除添加操作的时候</p>
</body>

</html>